﻿using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Windows.Forms;

namespace Demo
{
    public partial class DataAdd : Form
    {
        private int? entryId;
        private char fType;
        private string? currentFilePath;

        private bool isDragging;
        private Point dragOffset;

        public DataAdd()
        {
            InitializeComponent();
            entryId = null;
            fType = 'A';
            currentFilePath = null;

            WireRuntimeEvents();

            if (!IsDesignMode())
            {
                AttachDragHandler(groupControl1);
                AttachDragHandler(groupControl2);
                AttachDragHandler(groupControl3);
                AttachDragHandler(groupControl4);
                AttachDragHandler(groupControl5);
                AttachDragHandler(groupControl6);
                AttachDragHandler(groupControl8);
            }
        }

        public DataAdd(char fType, int? entryId = null) : this()
        {
            this.fType = fType;
            this.entryId = entryId;
        }

        private void WireRuntimeEvents()
        {
            toolStripButton2.Click += (_, __) =>
            {
                DialogResult = DialogResult.Cancel;
                Close();
            };
        }

        private void FrmTZ_Scan_Add_Load(object sender, EventArgs e)
        {
            InitializeDefaults();

            chkEnableReportPassword.CheckedChanged += (_, __) => UpdatePasswordInputState();
            UpdatePasswordInputState();

            if (entryId.HasValue)
            {
                Text = "編輯測試資料";
                LoadEntry(entryId.Value);
            }
            else
            {
                Text = "新增測試資料";
            }
        }

        private void InitializeDefaults()
        {
            dtpTestDate.Value = DateTime.Today;
            dtpBirthDate.Value = DateTime.Today;
            cmbGrade.SelectedIndex = -1;
            cmbParentEducation.SelectedIndex = -1;
        }

        private void UpdatePasswordInputState()
        {
            txtPasswordInput.Enabled = chkEnableReportPassword.Checked;
            if (!txtPasswordInput.Enabled)
            {
                txtPasswordInput.Clear();
            }
        }

        private void LoadEntry(int id)
        {
            try
            {
                using var connection = new SqlConnection(DatabaseConfig.ConnectionString);
                using var command = new SqlCommand(@"
SELECT ParameterNumber,
       MainTesterName,
       ChildName,
       TestDate,
       BirthDate,
       Grade,
       ParentEducation,
       PhoneNumber,
       VideoGame,
       Address,
       Remarks,
       ChildGender,
       HandPreference,
       Blocks,
       Comprehension,
       MatrixReasoning,
       BugSearch,
       PictureMemory,
       Similarities,
       PictureConcepts,
       Cancellation,
       AnimalHome,
       Puzzle,
       AnimalCoding,
       Understanding,
       PictureRecognition,
       PictureNaming,
       RandomCancellation,
       OrderedCancellation,
       ConfidenceLevel,
       StatisticalSignificance,
       ComparisonBasis,
       CalculationMethod,
       CalculationMethod2,
       FilePath,
       FType
FROM dbo.TestEntries
WHERE EntryID = @EntryID;", connection);
                command.Parameters.AddWithValue("@EntryID", id);

                connection.Open();
                using var reader = command.ExecuteReader();
                if (!reader.Read())
                {
                    DevExpress.XtraEditors.XtraMessageBox.Show("未找到對應的資料記錄。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    DialogResult = DialogResult.Cancel;
                    Close();
                    return;
                }

                entryId = id;

                var dbFType = reader["FType"]?.ToString();
                if (!string.IsNullOrWhiteSpace(dbFType))
                {
                    fType = dbFType![0];
                }

                txtParameterCode.Text = reader["ParameterNumber"]?.ToString();
                txtTesterName.Text = reader["MainTesterName"]?.ToString();
                txtChildName.Text = reader["ChildName"]?.ToString();

                if (reader["TestDate"] != DBNull.Value)
                {
                    dtpTestDate.Value = Convert.ToDateTime(reader["TestDate"]);
                }

                if (reader["BirthDate"] != DBNull.Value)
                {
                    dtpBirthDate.Value = Convert.ToDateTime(reader["BirthDate"]);
                }

                ApplyComboSelection(cmbGrade, reader["Grade"]?.ToString());
                ApplyComboSelection(cmbParentEducation, reader["ParentEducation"]?.ToString());

                txtPhoneNumber.Text = reader["PhoneNumber"]?.ToString();
                txtVideoGames.Text = reader["VideoGame"]?.ToString();
                txtContactAddress.Text = reader["Address"]?.ToString();
                memoParentRemark.Text = reader["Remarks"]?.ToString();

                SetGender(reader["ChildGender"]?.ToString());
                SetHandPreference(reader["HandPreference"]?.ToString());

                numBlock.Value = GetNumeric(reader["Blocks"], numBlock);
                numInformation.Value = GetNumeric(reader["Comprehension"], numInformation);
                numMatrix.Value = GetNumeric(reader["MatrixReasoning"], numMatrix);
                numBugSearch.Value = GetNumeric(reader["BugSearch"], numBugSearch);
                numPictureMemory.Value = GetNumeric(reader["PictureMemory"], numPictureMemory);
                numSimilarities.Value = GetNumeric(reader["Similarities"], numSimilarities);
                numConcepts.Value = GetNumeric(reader["PictureConcepts"], numConcepts);
                numCancellation.Value = GetNumeric(reader["Cancellation"], numCancellation);
                numAnimalHome.Value = GetNumeric(reader["AnimalHome"], numAnimalHome);
                numPuzzle.Value = GetNumeric(reader["Puzzle"], numPuzzle);
                numAnimalCoding.Value = GetNumeric(reader["AnimalCoding"], numAnimalCoding);
                numComprehension.Value = GetNumeric(reader["Understanding"], numComprehension);
                numPictureRecognition.Value = GetNumeric(reader["PictureRecognition"], numPictureRecognition);
                numPictureNaming.Value = GetNumeric(reader["PictureNaming"], numPictureNaming);
                numRandomCancellation.Value = GetNumeric(reader["RandomCancellation"], numRandomCancellation);
                numOrderedCancellation.Value = GetNumeric(reader["OrderedCancellation"], numOrderedCancellation);

                SetReliability(reader["ConfidenceLevel"]?.ToString());
                SetSignificance(reader["StatisticalSignificance"]?.ToString());
                SetComparisonBasis(reader["ComparisonBasis"]?.ToString());
                SetCalculationMethod(reader["CalculationMethod"]?.ToString());
                SetAlternativeMethod(reader["CalculationMethod2"]?.ToString());

                currentFilePath = reader["FilePath"]?.ToString();
            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show($"載入資料失敗：{ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private static void ApplyComboSelection(System.Windows.Forms.ComboBox comboBox, string? value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                comboBox.SelectedIndex = -1;
                return;
            }

            var index = comboBox.Items.IndexOf(value);
            comboBox.SelectedIndex = index;
        }

        private void SetGender(string? value)
        {
            if (string.Equals(value, "女性", StringComparison.OrdinalIgnoreCase))
            {
                radioGenderFemale.Checked = true;
            }
            else
            {
                radioGenderMale.Checked = true;
            }
        }

        private void SetHandPreference(string? value)
        {
            if (string.Equals(value, "左手", StringComparison.OrdinalIgnoreCase))
            {
                radioHandLeft.Checked = true;
            }
            else if (string.Equals(value, "不确定", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "不確定", StringComparison.OrdinalIgnoreCase))
            {
                radioHandUnknown.Checked = true;
            }
            else
            {
                radioHandRight.Checked = true;
            }
        }

        private void SetReliability(string? value)
        {
            if (string.Equals(value, "90%", StringComparison.OrdinalIgnoreCase))
            {
                radioReliability90.Checked = true;
            }
            else
            {
                radioReliability95.Checked = true;
            }
        }

        private void SetSignificance(string? value)
        {
            switch (value)
            {
                case "0.05":
                    radioSignificance005.Checked = true;
                    break;
                case "0.10":
                    radioSignificance010.Checked = true;
                    break;
                case "0.15":
                    radioSignificance015.Checked = true;
                    break;
                default:
                    radioSignificance001.Checked = true;
                    break;
            }
        }

        private void SetComparisonBasis(string? value)
        {
            radioComparisonOverall.Checked = true;
        }

        private void SetCalculationMethod(string? value)
        {
            if (string.Equals(value, "比例估算法", StringComparison.OrdinalIgnoreCase))
            {
                radioMethodProportion.Checked = true;
            }
            else if (string.Equals(value, "替代分检验", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "替代分檢驗", StringComparison.OrdinalIgnoreCase))
            {
                radioMethodReplacement.Checked = true;
            }
            else
            {
                radioMethodReplacement.Checked = true;
            }
        }

        private void SetAlternativeMethod(string? value)
        {
            if (string.Equals(value, "比例估算法", StringComparison.OrdinalIgnoreCase))
            {
                radioAlternativeProportion.Checked = true;
            }
            else if (string.Equals(value, "替代分检验", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "替代分檢驗", StringComparison.OrdinalIgnoreCase))
            {
                radioAlternativeReplacement.Checked = true;
            }
            else
            {
                radioAlternativeReplacement.Checked = true;
            }
        }

        private static decimal GetNumeric(object value, NumericUpDown control)
        {
            if (value == DBNull.Value)
            {
                return control.Minimum;
            }

            var decimalValue = Convert.ToDecimal(value);
            if (decimalValue < control.Minimum)
            {
                return control.Minimum;
            }

            if (decimalValue > control.Maximum)
            {
                return control.Maximum;
            }

            return decimalValue;
        }

        private bool ValidateInputs()
        {
            if (string.IsNullOrWhiteSpace(txtParameterCode.Text))
            {
                ShowValidation("請輸入參數編號。", txtParameterCode);
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtTesterName.Text))
            {
                ShowValidation("請輸入主試名字。", txtTesterName);
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtChildName.Text))
            {
                ShowValidation("請輸入兒童名字。", txtChildName);
                return false;
            }

            return true;
        }

        private void ShowValidation(string message, Control control)
        {
            DevExpress.XtraEditors.XtraMessageBox.Show(message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            control.Focus();
        }

        private string GetSelectedGender() => radioGenderFemale.Checked ? "女性" : "男性";

        private string GetSelectedHandPreference()
        {
            if (radioHandLeft.Checked)
            {
                return "左手";
            }

            if (radioHandUnknown.Checked)
            {
                return "不確定";
            }

            return "右手";
        }

        private string GetSelectedReliability() => radioReliability90.Checked ? "90%" : "95%";

        private string GetSelectedSignificance()
        {
            if (radioSignificance005.Checked)
            {
                return "0.05";
            }

            if (radioSignificance010.Checked)
            {
                return "0.10";
            }

            if (radioSignificance015.Checked)
            {
                return "0.15";
            }

            return "0.01";
        }

        private string GetSelectedComparisonBasis() => "全樣本";

        private string GetSelectedCalculationMethod() => radioMethodProportion.Checked ? "比例估算法" : "替代分檢驗";

        private string GetSelectedAlternativeMethod() => radioAlternativeProportion.Checked ? "比例估算法" : "替代分檢驗";

        private static string? GetComboSelectionValue(System.Windows.Forms.ComboBox comboBox)
        {
            return comboBox.SelectedIndex >= 0 ? comboBox.SelectedItem?.ToString() : null;
        }

        private static object ToDbValue(string? value)
        {
            return string.IsNullOrWhiteSpace(value) ? DBNull.Value : value.Trim();
        }

        private static void AddScoreParameter(SqlCommand command, string name, NumericUpDown control)
        {
            var parameter = new SqlParameter(name, SqlDbType.Decimal)
            {
                Precision = 10,
                Scale = 2,
                Value = control.Value
            };
            command.Parameters.Add(parameter);
        }

        private static string ResolveUserAccount()
        {
            return string.IsNullOrWhiteSpace(SessionContext.UserAccount)
                ? Environment.UserName
                : SessionContext.UserAccount;
        }

        private void SaveEntry()
        {
            if (!ValidateInputs())
            {
                return;
            }

            try
            {
                using var connection = new SqlConnection(DatabaseConfig.ConnectionString);
                using var command = new SqlCommand("dbo.usp_SaveTestEntry", connection)
                {
                    CommandType = CommandType.StoredProcedure
                };

                command.Parameters.AddWithValue("@EntryID", (object?)entryId ?? DBNull.Value);
                command.Parameters.AddWithValue("@ParameterNumber", txtParameterCode.Text.Trim());
                command.Parameters.AddWithValue("@MainTesterName", txtTesterName.Text.Trim());
                command.Parameters.AddWithValue("@ChildName", txtChildName.Text.Trim());
                command.Parameters.AddWithValue("@TestDate", dtpTestDate.Value.Date);
                command.Parameters.AddWithValue("@BirthDate", dtpBirthDate.Value.Date);
                command.Parameters.AddWithValue("@Grade", ToDbValue(GetComboSelectionValue(cmbGrade)));
                command.Parameters.AddWithValue("@ParentEducation", ToDbValue(GetComboSelectionValue(cmbParentEducation)));
                command.Parameters.AddWithValue("@PhoneNumber", ToDbValue(txtPhoneNumber.Text));
                command.Parameters.AddWithValue("@VideoGame", ToDbValue(txtVideoGames.Text));
                command.Parameters.AddWithValue("@Address", ToDbValue(txtContactAddress.Text));
                command.Parameters.AddWithValue("@Remarks", ToDbValue(memoParentRemark.Text));
                command.Parameters.AddWithValue("@ChildGender", GetSelectedGender());
                command.Parameters.AddWithValue("@HandPreference", GetSelectedHandPreference());

                AddScoreParameter(command, "@Blocks", numBlock);
                AddScoreParameter(command, "@Comprehension", numInformation);
                AddScoreParameter(command, "@MatrixReasoning", numMatrix);
                AddScoreParameter(command, "@BugSearch", numBugSearch);
                AddScoreParameter(command, "@PictureMemory", numPictureMemory);
                AddScoreParameter(command, "@Similarities", numSimilarities);
                AddScoreParameter(command, "@PictureConcepts", numConcepts);
                AddScoreParameter(command, "@Cancellation", numCancellation);
                AddScoreParameter(command, "@AnimalHome", numAnimalHome);
                AddScoreParameter(command, "@Puzzle", numPuzzle);
                AddScoreParameter(command, "@AnimalCoding", numAnimalCoding);
                AddScoreParameter(command, "@Understanding", numComprehension);
                AddScoreParameter(command, "@PictureRecognition", numPictureRecognition);
                AddScoreParameter(command, "@PictureNaming", numPictureNaming);
                AddScoreParameter(command, "@RandomCancellation", numRandomCancellation);
                AddScoreParameter(command, "@OrderedCancellation", numOrderedCancellation);

                command.Parameters.AddWithValue("@ConfidenceLevel", GetSelectedReliability());
                command.Parameters.AddWithValue("@StatisticalSignificance", GetSelectedSignificance());
                command.Parameters.AddWithValue("@ComparisonBasis", GetSelectedComparisonBasis());
                command.Parameters.AddWithValue("@CalculationMethod", GetSelectedCalculationMethod());
                command.Parameters.AddWithValue("@CalculationMethod2", GetSelectedAlternativeMethod());
                command.Parameters.AddWithValue("@FilePath", ToDbValue(currentFilePath));
                command.Parameters.AddWithValue("@FType", fType.ToString());
                command.Parameters.AddWithValue("@UserAccount", ResolveUserAccount());

                var resultCodeParam = new SqlParameter("@ResultCode", SqlDbType.Int)
                {
                    Direction = ParameterDirection.Output
                };
                var resultMessageParam = new SqlParameter("@ResultMessage", SqlDbType.NVarChar, 200)
                {
                    Direction = ParameterDirection.Output
                };
                command.Parameters.Add(resultCodeParam);
                command.Parameters.Add(resultMessageParam);

                connection.Open();
                command.ExecuteNonQuery();

                var resultCode = resultCodeParam.Value != DBNull.Value ? Convert.ToInt32(resultCodeParam.Value) : 0;
                var resultMessage = resultMessageParam.Value?.ToString();

                if (resultCode != 0)
                {
                    var message = string.IsNullOrWhiteSpace(resultMessage) ? "儲存失敗，請稍後再試。" : resultMessage;
                    DevExpress.XtraEditors.XtraMessageBox.Show(message, "儲存失敗", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                DialogResult = DialogResult.OK;
                Close();
            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show($"儲存過程中出現錯誤：{ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
		}

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            SaveEntry();
        }

        private bool IsDesignMode()
        {
            return LicenseManager.UsageMode == LicenseUsageMode.Designtime;
        }

        private void AttachDragHandler(Control control)
        {
            control.MouseDown += Control_MouseDown;
            control.MouseMove += Control_MouseMove;
            control.MouseUp += Control_MouseUp;
        }

        private void Control_MouseDown(object? sender, MouseEventArgs e)
        {
            if (sender is Control ctrl && e.Button == MouseButtons.Left)
            {
                isDragging = true;
                dragOffset = new Point(e.X, e.Y);
                ctrl.Capture = true;
            }
        }

        private void Control_MouseMove(object? sender, MouseEventArgs e)
        {
            if (isDragging && sender is Control ctrl)
            {
                var newLocation = ctrl.Location;
                newLocation.Offset(e.X - dragOffset.X, e.Y - dragOffset.Y);
                ctrl.Location = newLocation;
            }
        }

        private void Control_MouseUp(object? sender, MouseEventArgs e)
        {
            if (sender is Control ctrl)
            {
                isDragging = false;
                ctrl.Capture = false;
            }
        }
    }
}
